//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

#include "EventManager/EventManager.h"
#include "Game/Events/EvTouchScreen.h"
#include "TouchScreenBase.h"
#include "Application.h"
#include "GameStates/GameStates.h"
//#include "GLLive/GLLiveobject.h"
#include "Lib2D/UIInfo.h"
#include "Lib2D/UIAnimPlayer.h"
#include "Lib2D/Sprite.h"
#include "Lib2D/Font.h"
#include "Lib2D/SpriteManager.h"
#include "Strings/Strings.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef FPS_USE_GUI
using namespace irr;
using namespace core;
#endif //FPS_USE_GUI

//#ifdef USE_GLLIVE
//extern CGLLiveobject* g_pGLLiveObj;
//#endif

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Ctors / Dtor
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

TouchScreenBase::TouchScreenBase(E_TouchPriority priority)
{
	m_lastUpdateTimestamp = 0;

	m_touchPriority = priority;

	m_state = E_TOUCH_STATE_NORMAL;

	m_bIsVisible = true;

	m_allTargetInfos.clear();
	
	m_pPlayer = NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

TouchScreenBase::~TouchScreenBase()
{
	std::map<int, TouchTargetData *>::iterator itr1  =  m_allTargetInfos.begin();
	for(;itr1!=m_allTargetInfos.end(); ++itr1 )
	{
		delete itr1->second;
	}
	m_allTargetInfos.clear();
}

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Methods (Events)//
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TouchScreenBase::touchBegan(const TouchPoint& point, TouchID touchID, bool isDoubleTap)
{
#if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
 #ifdef FPS_USE_GUI
	irr::SEvent event;
	event.EventType = irr::EET_MOUSE_INPUT_EVENT;
	event.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
	event.MouseInput.X = point.X;
	event.MouseInput.Y = point.Y;

	Application* app = Application::instance();
	IrrlichtDevice* dev = app->GetDevice();
	if (dev)
		dev->postEventFromUser(event);
	#endif //
#endif //

	/*
	if (!m_rect.isPointInside(point))
	{
		return;
	}*/

//#ifdef USE_GLLIVE
//	if	(g_pGLLiveObj->isRun()){
//		g_pGLLiveObj->touchesBegan(point.X, point.Y);
//	
//	}else
//#endif//USE_GLLIVE
	{
		const  EvTouchScreenPress e(touchID, point.X, point.Y, true);
		EventManager::instance()->raiseAsync(e);

		TouchScreenBase* pReceiver = NULL;

		for(EventReceiverListIter iter = Application::instance()->CurrentState()->GetEventReceivers().begin();
			iter != Application::instance()->CurrentState()->GetEventReceivers().end(); ++iter)
		{
			if ((*iter)->m_rect.isPointInside(point))
			{
				if (!pReceiver || pReceiver->m_touchPriority < (*iter)->m_touchPriority)
				{
					pReceiver = (*iter);
				}
			}
		}

		if (pReceiver)
		{
			pReceiver->touchBegan(point, touchID,isDoubleTap);
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TouchScreenBase::touchMoved(const TouchPoint& point, TouchID touchID)
{
#if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
	#ifdef FPS_USE_GUI
	irr::SEvent event;
	event.EventType = irr::EET_MOUSE_INPUT_EVENT;
	event.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
	event.MouseInput.X = point.X;
	event.MouseInput.Y = point.Y;

	Application* app = Application::instance();
	IrrlichtDevice* dev = app->GetDevice();
	if (dev)
		dev->postEventFromUser(event);																		   
	#endif//
#endif //FPS_USE_GUI

//#ifdef USE_GLLIVE
//	if	(g_pGLLiveObj->isRun()){
//		g_pGLLiveObj->touchesMove(point.X, point.Y);	
//	}else
//#endif//USE_GLLIVE
	{
		//add by luochangying
		const  EvTouchScreenMove e(touchID, point.X, point.Y);
		EventManager::instance()->raiseAsync(e);

		for(EventReceiverListIter iter = Application::instance()->CurrentState()->GetEventReceivers().begin();
			iter != Application::instance()->CurrentState()->GetEventReceivers().end(); ++iter)
		{
			(*iter)->touchMoved(point, touchID);
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TouchScreenBase::touchEnded(const TouchPoint& point, TouchID touchID)
{
#if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
	#ifdef FPS_USE_GUI
	irr::SEvent event;
	event.EventType = irr::EET_MOUSE_INPUT_EVENT;
	event.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP;
	event.MouseInput.X = point.X;
	event.MouseInput.Y = point.Y;

	Application* app = Application::instance();
	IrrlichtDevice* dev = app->GetDevice();
	if (dev)
		dev->postEventFromUser(event);			
	#endif
#endif //FPS_USE_GUI

//#ifdef USE_GLLIVE
//	if	(g_pGLLiveObj->isRun()){
//		g_pGLLiveObj->touchesEnded(point.X, point.Y);	
//	}else
//#endif//USE_GLLIVE
	{
		const EvTouchScreenPress e(touchID, point.X, point.Y, false);
		EventManager::instance()->raiseAsync(e);

		for(EventReceiverListIter iter = Application::instance()->CurrentState()->GetEventReceivers().begin();
			iter != Application::instance()->CurrentState()->GetEventReceivers().end(); ++iter)
		{
			(*iter)->touchEnded(point, touchID);
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TouchScreenBase::touchCancelled(const TouchPoint& point, TouchID touchID)
{
//#ifdef USE_GLLIVE
//	if	(g_pGLLiveObj->isRun()){
//		g_pGLLiveObj->touchesEnded(point.X, point.Y);	
//	}else
//#endif//USE_GLLIVE
	{
		const EvTouchScreenPress e(touchID, point.X, point.Y, false);
		EventManager::instance()->raiseAsync(e);

		for(EventReceiverListIter iter = Application::instance()->CurrentState()->GetEventReceivers().begin();
			iter != Application::instance()->CurrentState()->GetEventReceivers().end(); ++iter)
		{
			(*iter)->touchCancelled(point, touchID);
		}
	}
}

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Methods (IUpdatable impl.)
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TouchScreenBase::update(TimeStamp timestamp)
{

#if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
	{
		int touchQueueLast = s_touchQueueLast;

		touchQueueLast = (touchQueueLast + 1) & (TOUCH_QUEUE_SIZE - 1);

		while(s_touchQueueFirst != touchQueueLast)
		{
			TouchQueue& touch = s_touchQueue[s_touchQueueFirst];

			const TouchPoint& point = TouchPoint(touch.x, touch.y);

			switch(touch.type)
			{
			case TOUCH_QUEUE_EVENT_TOUCH:
				touchBegan(point, touch.id, touch.DoubleTap);
				break;

			case TOUCH_QUEUE_EVENT_MOVE:
				touchMoved(point, touch.id);
				break;

			case TOUCH_QUEUE_EVENT_UNTOUCH:
				touchEnded(point, touch.id);
				break;
			}

			s_touchQueueFirst = (s_touchQueueFirst + 1) & (TOUCH_QUEUE_SIZE - 1);
		}
	}
#endif

	m_lastUpdateTimestamp = timestamp;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TouchScreenBase::RegisterForEvents(TouchScreenBase* cls)
{
	if(cls)
	{
		Application::instance()->CurrentState()->GetEventReceivers().push_back(cls);
		//m_eventReceivers.push_back(cls);
	}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TouchScreenBase::UnRegisterForEvents(TouchScreenBase* cls)
{
	if(cls)
	{
		Application::instance()->CurrentState()->GetEventReceivers().remove(cls);
		//m_eventReceivers.remove(cls);
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

volatile int							TouchScreenBase::s_touchQueueFirst	=	0;
volatile int							TouchScreenBase::s_touchQueueLast	=	-1;
struct TouchScreenBase::TouchQueue		TouchScreenBase::s_touchQueue[TOUCH_QUEUE_SIZE];

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Notice: we must guarantee the x, y as the original(unscaled) position to remain the compare in the same unscaled ratio cause we won't update the size or other informations while the screen size changed.
//If we need the exact scaled info indeed, we should adopt another case that we should store the scaled info instead of the original info.
void TouchScreenBase::AddTouchEvent(int type, int x, int y, long id, bool DoubleTap)
{
	s_touchQueueLast = (s_touchQueueLast + 1) & (TOUCH_QUEUE_SIZE - 1);

	TouchQueue& touch = s_touchQueue[s_touchQueueLast];

	touch.type	=	type;
	touch.x		=	UIInfo::instance()->GetUI_SCALED_2_ORI_X(x);
	touch.y		=	UIInfo::instance()->GetUI_SCALED_2_ORI_Y(y);
	touch.id	=	id;
	touch.DoubleTap = DoubleTap;
}

void TouchScreenBase::ChangeRect(const irr::core::rect<short> &rt)
{
	m_rect = rt;
}

void TouchScreenBase::ChangeTouchState( E_TouchState state) 
{
	m_state = state; 
}

E_TouchState TouchScreenBase::GetTouchState()
{
	return m_state;
}

void TouchScreenBase::UpdateTouchState()
{
	switch( m_state )
	{
	case E_TOUCH_STATE_CREATE:
		if( IsCreateProcessFinished() )
		{
			m_state = E_TOUCH_STATE_NORMAL;
		}
		break;
	case E_TOUCH_STATE_RELEASE:
		break;
	case E_TOUCH_STATE_TOUCH:
		//if( IsExitTouchProcessFinished() )
		//{
		//	m_state = E_TOUCH_STATE_NORMAL;
		//}
		break;
	case E_TOUCH_STATE_DISABLE:
		if( IsEnableProcessFinished() )
		{
			m_state = E_TOUCH_STATE_NORMAL;
		}
		break;
	case E_TOUCH_STATE_CHANGE:
		if( IsExitChangeProcessFinished() )
		{
			m_state = E_TOUCH_STATE_NORMAL;
		}
		break;
	case E_TOUCH_STATE_HIDE:
		if( IsShowProcessFinished() )
		{
			m_state = E_TOUCH_STATE_NORMAL;
		}
		break;
	case E_TOUCH_STATE_NORMAL:
	default:
		break;
	}
}

bool TouchScreenBase::IsCreateProcessFinished()
{
	return true;
}

bool TouchScreenBase::IsExitTouchProcessFinished()
{
	return true;
}

bool TouchScreenBase::IsExitChangeProcessFinished()
{
	return true;
}
bool TouchScreenBase::IsShowProcessFinished()
{
	return true;
}
bool TouchScreenBase::IsEnableProcessFinished()
{
	return true;
}

bool TouchScreenBase::IsExitProcessFinished()
{
	return true;
}
void TouchScreenBase::SetAnimPlayer(UIAnimPlayer *p)
{
	m_pPlayer = p;
}

bool TouchScreenBase::HasPlayingAnimation()
{
	if( m_pPlayer == NULL )
	{
		return false;
	}

	if( m_pPlayer )
	{
		switch( m_state )
		{
		case E_TOUCH_STATE_NORMAL:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimNormal ) )
			{
				return true;
			}
			return false;
			break;
		case E_TOUCH_STATE_CREATE:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimEnter ) )
			{
				return true;
			}
			return false;
			break;
		case E_TOUCH_STATE_RELEASE:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimExit ) )
			{
				return true;
			}
			return false;
			break;
		case E_TOUCH_STATE_TOUCH:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimEnterTouch ) )
			{
				return true;
			}
			else if( m_pPlayer->HasAnim( UI_ANIMATION::AnimExitTouch ) )
			{
				return true;
			}
			return false;
			break;
		case E_TOUCH_STATE_DISABLE:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimEnable ) )
			{
				return true;
			}
			else if( m_pPlayer->HasAnim( UI_ANIMATION::AnimDisable ) )
			{
				return true;
			}
			return false;
			break;
		case E_TOUCH_STATE_CHANGE:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimChange ) )
			{
				return true;
			}
			return false;
			break;
		case E_TOUCH_STATE_HIDE:
			if( m_pPlayer->HasAnim( UI_ANIMATION::AnimHide ) )
			{
				return true;
			}
			else if( m_pPlayer->HasAnim( UI_ANIMATION::AnimShow ) )
			{
				return true;
			}
			return false;
			break;
		}
		return false;
	}
	return false;
}

void TouchScreenBase::SetVisible(bool bVisible)
{
	m_bIsVisible = bVisible;
}
bool TouchScreenBase::IsVisible()
{
	return m_bIsVisible;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool TouchScreenBase::IsExistTargetInfo(E_TouchTargetType targetType, int targetIndex)
{
	int targetKey = targetType<<16;
	targetKey += targetIndex;

	std::map<int, TouchTargetData *>::iterator itr;
	itr = m_allTargetInfos.find( targetKey );
	if( itr != m_allTargetInfos.end() )
	{
		return true;
	}
	return false;
}

void TouchScreenBase::DrawTarget(E_TouchTargetType targetType,int targetIndex, int x, int y, float rotz, int alpha, float scale)
{
	int targetKey = targetType<<16;
	targetKey += targetIndex;

	std::map<int, TouchTargetData *>::iterator itr;
	itr = m_allTargetInfos.find( targetKey );
	if( itr == m_allTargetInfos.end() )
	{
		return;
	}

	switch( targetType )
	{
	case E_TouchTarget_Image:
		{
			TouchTargetData *pData = itr->second;
			DrawImageByTargetData( pData, x, y, rotz,alpha, scale );
			return;
		}
		break;
	case E_TouchTarget_Text:
		{
			TouchTargetData *pData = itr->second;
			DrawTextByTargetData( pData, x, y, rotz,alpha, scale );
			return;
		}
		break;
	default:
		break;
	}
}

void TouchScreenBase::AddTargetInfo( E_TouchTargetType targetType,int targetIndex ,int x, int y, const char *name, int msgIndex )
{
	TouchTargetData *pData = new TouchTargetData( x,y, name, msgIndex, targetType );
	int targetKey = targetType<<16;
	targetKey += targetIndex;

	std::pair<int, TouchTargetData *> value( targetKey , pData);
	m_allTargetInfos.insert( value );
}

void TouchScreenBase::AddTargetInfo( E_TouchTargetType targetType,int targetIndex ,int x, int y, const char *name, int msgIndex , const char* pFontName,int Anchor)
{
	TouchTargetData *pData = new TouchTargetData(x,y, name, msgIndex, targetType ,pFontName,Anchor);
	int targetKey = targetType<<16;
	targetKey += targetIndex;

	m_allTargetInfos.insert( std::pair<int, TouchTargetData *>( targetKey , pData) );
}

void TouchScreenBase::ChangeExistTargetInfo( E_TouchTargetType targetType,int targetIndex ,int x, int y, const char *name, int msgIndex )
{
	int targetKey = targetType<<16;
	targetKey += targetIndex;

	std::map<int, TouchTargetData *>::iterator itr;
	itr = m_allTargetInfos.find( targetKey );
	if( itr == m_allTargetInfos.end() )
	{
		return;
	}
	
	TouchTargetData *pData = itr->second;
	pData->m_posX = x;
	pData->m_posY = y;
	pData->m_groupName = name;
	pData->m_messageIndex = msgIndex;
}

void TouchScreenBase::DrawImageByTargetData(TouchTargetData *pData, int x, int y, float rotz, int alpha, float scale)
{
	CSprite* pSprite = CSpriteManager::instance()->GetSprite(pData->m_groupName.c_str() );
	if( pSprite == NULL )
	{
		int val = CSpriteManager::instance()->LoadSprite(pData->m_groupName.c_str(),false);
		if( val!= 1 )
		{
			return;
		}
		pSprite = CSpriteManager::instance()->GetSprite(pData->m_groupName.c_str() );
		if( pSprite == NULL )
		{
			return;
		}
	}

	float angleOld =  pSprite->GetAngle();
	float scaleOld =  pSprite->GetScale();
	if(rotz != 0.0f )
	{
		pSprite->SetAngle(rotz);
	}

	if( scale!= 1.0f)
	{
		pSprite->SetScale( scale );
	}

	bool textureAlpha = pSprite->m_pMaterial->getFlag(irr::video::EMF_2D_USE_TEXTURE_ALPHA);
	bool vertexAlpha = pSprite->m_pMaterial->getFlag(irr::video::EMF_2D_USE_VERTEX_ALPHA);			
	if( alpha != 255 )
	{
		pSprite->m_pMaterial->setFlag(irr::video::EMF_2D_USE_TEXTURE_ALPHA,false);
		pSprite->m_pMaterial->setFlag(irr::video::EMF_2D_USE_VERTEX_ALPHA,true);
	}

	pSprite->PaintFrame(pData->m_messageIndex, x, y, 0, alpha);

	pSprite->SetAngle(angleOld);
	pSprite->SetScale(scaleOld);

	if( alpha != 255 )
	{
		pSprite->m_pMaterial->setFlag(irr::video::EMF_2D_USE_TEXTURE_ALPHA,textureAlpha);
		pSprite->m_pMaterial->setFlag(irr::video::EMF_2D_USE_VERTEX_ALPHA,vertexAlpha);
	}
}
void TouchScreenBase::DrawTextByTargetData(TouchTargetData *pData, int x, int y, float rotz, int alpha, float scale)
{
	GX_CHAR* pText = Application::instance()->GetStringPack()->GetString(pData->m_messageIndex);	
	if(pText)
	{
		CFont *pFont = CSpriteManager::instance()->GetFont(pData->m_fontName.c_str());
		pFont->SetAngle(rotz);
		pFont->SetScale(scale);
		pFont->DrawString(pText, x, y, A_HCENTER | A_VCENTER, alpha);
		pFont->SetAngle(0.0f);
		pFont->SetScale(1.0f);
	}
}

void TouchScreenBase::GetTargetPositionInfo(E_TouchTargetType targetType,int targetIndex, int &x, int &y)
{
	int targetKey = targetType<<16;
	targetKey += targetIndex;

	std::map<int, TouchTargetData *>::iterator itr;
	itr = m_allTargetInfos.find( targetKey );
	if( itr == m_allTargetInfos.end() )
	{
		return;
	}

	TouchTargetData *pData = itr->second;
	x = pData->m_posX;
	y = pData->m_posY;
}

void TouchScreenBase::Restore()
{

}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////